local DBAniEventType = require("dragonbones.AnimationEventType")

local Role = import(".Role")
local Utils = require("app.utils.Util")

local NodeGetPositionFunc = cc.Node.getPosition
local NodeSetPositionFunc = cc.Node.setPosition
local NodeGetPositionXFunc = cc.Node.getPositionX
local NodeSetPositionXFunc = cc.Node.setPositionX
local NodeGetPositionYFunc = cc.Node.getPositionY
local NodeSetPositionYFunc = cc.Node.setPositionY
local NodeIsVisibleFunc = cc.Node.isVisible
local NodeSetVisibleFunc = cc.Node.setVisible
local NodeToWorldPosition = cc.Node.toWorldPosition
local NodeGetScaleFunc = cc.Node.getScale
local NodeSetScaleFunc = cc.Node.setScale
local NodeGetScaleXFunc = cc.Node.getScaleX
local NodeSetScaleXFunc = cc.Node.setScaleX
local NodeGetScaleYFunc = cc.Node.getScaleY
local NodeSetScaleYFunc = cc.Node.setScaleY
local NodeSetLocalZOrderFunc = cc.Node.setLocalZOrder
local NodeGetLocalZOrderFunc = cc.Node.getLocalZOrder

local MathFloor = math.floor
local MathRandom = math.random
local MathAbs = math.abs
local StringLen = string.len

local otherPlayerUpdateInterval = 1/24

local Character = class("Character",function()
    return Role.new()
end)

function Character:ctor(userBaseInfo, isSelf)
    cc(self):addComponent("components.behavior.EventProtocol"):exportMethods()

    if not isSelf then isSelf = false end
    self:setMySelf(isSelf)
    self:init(userBaseInfo)
end

function Character:init(userBaseInfo)
    self._userBaseInfo = userBaseInfo
    self.mAction = Role.ACTION_MAP_IDLE
    -- self.moveDir = cc.p(0,0)
    self.mDirectionX = Role.DIR_LEFT -- 和 Role里面的 setDirection 保持一致
    self:setEventMoveSpeed(self:getSpeed())
    self.mWaitStyleSeconds = 0
    self.mScale = 1.0
    self:setLine(Role.LINE_1)
    self.mStopMove = false
    self._behavior = Enums.behaviorType.none
    self._bloodData = nil

    if userBaseInfo.isUseAsyncLoad == nil then
        self.isUseAsyncLoad = true
    else
        self.isUseAsyncLoad = userBaseInfo.isUseAsyncLoad
    end

    if userBaseInfo.mountID and userBaseInfo.mountID > 0 then
        self:setMountId(userBaseInfo.mountID)
        self.mGetOnRide = true
    else
        self:setMountId(0)
        self.mGetOnRide = false
    end

    self:switchActions()
    self.mAction = self.ACTION_IDLE

    self:buildArmatureNode(function()
        self:playAni(self:getCurAction(),0)
    end)

    self:setSpeed(self._userBaseInfo.speed)

    self:setNodeEventEnabled(true)

    self._isEquipAnimationFinished = true
end

function Character:setUserBaseInfo(userBaseInfo)
    self._userBaseInfo = userBaseInfo
    self:buildArmatureNode(function()
        self:playAni(self:getCurAction(),0)
        self:setName(userBaseInfo.name)
        self:getOnRide(userBaseInfo.mountID)
    end)
end

function Character:getUserBaseInfo()
    return self._userBaseInfo
end

function Character:onExit()
    if self.mIMBubble then
        self.mIMBubble:removeFromParent()
        self.mIMBubble = nil
    end
end

function Character:setPartners(partners)
    self._partners = partners
end

function Character:getPartners()
    return self._partners or {}
end

function Character:setAllOpacity(opacity)
    self:setOpacity(opacity)
    if self.mHeadNameNode then
        self.mHeadNameNode:setOpacity(opacity)
    end
    if self.mBehaviorNode then
        self.mBehaviorNode:setOpacity(opacity)
    end
    if self.mMatchNode then
        self.mMatchNode:setOpacity(opacity)
    end
    if self.mTitleIconNode then
        self.mTitleIconNode:setOpacity(opacity)
    end
    if self.mBubble then
        self.mBubble:setOpacity(opacity)
    end
    if self.mIMBubble then
        self.mIMBubble:setOpacity(opacity)
    end
    if self.mGatherUi then
        self.mGatherUi:setOpacity(opacity)
    end
end

function Character:excuteAction(action, opacity)
    self:runAction(action)
    if self.mHeadNameNode then
        self.mHeadNameNode:runAction(action:clone())
    end
    if self.mMatchNode then
        self.mMatchNode:runAction(action:clone())
    end
    if self.mTitleIconNode then
        self.mTitleIconNode:runAction(action:clone())
    end
    if self.mBubble then
        self.mBubble:runAction(action:clone())
    end
    if self.mGatherUi then
        self.mGatherUi:runAction(action:clone())
    end

    if not opacity then
        print("Error, Character:excuteAction, opacity = nil")
        dump(debug.traceback())
        opacity = 0
    end

    -- 动画的话不做过渡处理，直接设置透明度
    if self.mBehaviorNode then
        self.mBehaviorNode:setOpacity(opacity)
    end
end

function Character:excuteStopAllActions()
    self:stopAllActions()
    if self.mHeadNameNode then
        self.mHeadNameNode:stopAllActions()
    end
    if self.mMatchNode then
        self.mMatchNode:stopAllActions()
    end
    if self.mTitleIconNode then
        self.mTitleIconNode:stopAllActions()
    end
    if self.mBubble then
        self.mBubble:stopAllActions()
    end
    if self.mGatherUi then
        self.mGatherUi:stopAllActions()
    end
end

function Character:updateUpHead()
    if not self.mHeadNameNode then return end

    self:upHeadNodeVisibility(true)
end

-- 设置人物头顶信息是否显示（当设置里 设置了不显示，就永不显示）
function Character:upHeadNodeVisibility(visible)
    if not self.mHeadNameNode then return end

    if not UD.setting:isShowPlayerUpHead() or FieldManager._hideAllCharacterUpHead then
        visible = false
    end

    NodeSetVisibleFunc(self.mHeadNameNode, visible)
    if self.mBehaviorNode then
        NodeSetVisibleFunc(self.mBehaviorNode, visible)
    end
end

function Character:allVisibility(visible)
    self:upHeadNodeVisibility(visible)

    if not visible then
        self:hideBattleMark()
    end

    if not visible then
        self:hideIMBubble()
    end
end

function Character:removeAll()
    if self.mBubble then
        self.mBubble:removeFromParent()
        self.mBubble = nil
    end
    if self.mHeadNameNode then
        self.mHeadNameNode:removeFromParent()
        self.mHeadNameNode = nil
    end
    if self.mBehaviorNode then
        self.mBehaviorNode:removeFromParent()
        self.mBehaviorNode = nil
        self._behavior = Enums.behaviorType.none
        self._bloodData = nil
    end
    if self.mMatchNode then
        self.mMatchNode:removeFromParent()
        self.mMatchNode = nil
    end
end

function Character:showBattleMark()
    -- 开战时角色头顶的感叹号
    local markNode,actionName = self.mBattleMarkNode,self.mBattleMarkAction
    if not markNode then
        markNode , actionName  = NodeFactory:createBattleMark()
        self.mBattleMarkNode = markNode
        self.mBattleMarkAction = actionName
        self:addChild(markNode)
    end

    local x,y = self:getPointWorldPos()

    local posX,posY = self:toLocalPosition(x,y)
    NodeSetVisibleFunc(markNode,true)
    NodeSetPositionFunc(markNode,posX,posY)
    markNode:play(actionName,1)
end

function Character:hideBattleMark()
    if not self.mBattleMarkNode then return end
    NodeSetVisibleFunc(self.mBattleMarkNode,false)
end

function Character:getRandomLine()
    local userType = tonumber(self:getUid()) % 10
    if userType == 0 then
        return Role.LINE_3
    else
        return Role.LINE_1
    end  
end

function Character:setLine(line)
    Role.setLine(self,line)
    self:updateNameZOrder()
end

function Character:resetLine()
    if self:getLine() == self:getOriginalLine() then
        return
    end
    self:setLine(self:getOriginalLine())
end

function Character:addDefStyleAction()
    self:addStyleAction(Res.PlayerStyleAction)
    self:randomStyleAction()
end

function Character:addStyleAction(style)
    if not self.mStyleActions then
        self.mStyleActions = {}
    end

    table.insert(self.mStyleActions,style)
end

function Character:randomStyleAction()
    local len = #self.mStyleActions
    if len < 1 then
        return
    end

    local rand = MathRandom(1,len)
    local style = self.mStyleActions[rand]
    self:setStyleAction(style.action)
    self:setStyleMinSeconds(style.minSeconds)
    self:setStyleMaxSeconds(style.maxSeconds)
end

function Character:setStyleAction(styleAction)
    self.mStyleAction = styleAction
end

function Character:getStyleAction()
    return self.mStyleAction
end

function Character:setStyleMinSeconds(minSeconds)
    self.mMinStyleSeconds = minSeconds
end

function Character:getStyleMinSeconds()
    return self.mMinStyleSeconds
end

function Character:setStyleMaxSeconds(maxSeconds)
    self.mMaxStyleSeconds = maxSeconds
end

function Character:getStyleMaxSeconds()
    return self.mMaxStyleSeconds
end

function Character:countStyleSeconds()
    self.mStyleSeconds = MathRandom(self:getStyleMinSeconds(),self:getStyleMaxSeconds())
end

function Character:updatePlayStyleAction(dt)
    if not self.mArmatrueNode then return end
    if not self:isMySelf() then
        return
    end

    if self:isGetOnRide() then
        return
    end

    if not self:getStyleAction() then
        return
    end

    if StoryManager:isEnterStoryMode() or self:getCurAction() ~= self.ACTION_IDLE or not app:isBattleGuideComp() then
        self.mWaitStyleSeconds = 0
        return
    end

    self.mWaitStyleSeconds = self.mWaitStyleSeconds + dt
    if not self.mStyleSeconds then
        self:countStyleSeconds()
    end

    if self.mWaitStyleSeconds >= self.mStyleSeconds then
        self.mWaitStyleSeconds = 0
        self:countStyleSeconds()

        
        local function callback()
            self:forceStandby()
            self:randomStyleAction()
        end

        local function loopCallback()
            self:forceStandby()
            self:randomStyleAction()
        end

        -- self:getOffRide(true)
        self:setAction(self:getStyleAction(), false)
        self.mArmatrueNode:play(self:getStyleAction(),1,callback,loopCallback)
    end
end

---
-- cc.c3b(0,0,0)
--
function Character:setNameColor(color)
    local headNameNode = self.mHeadNameNode
    if headNameNode then
        headNameNode:setNameColor(color)
    end
end

function Character:toNormalColor()
    --非公会成员 124 200 169
    --公会成员 124 203 87
    if self:getNameColorStatus() == "normal" then return end
    self:setNameColorStatus("normal")
    self:updateNameColors()
end

function Character:toTeamColor()
    if self:getNameColorStatus() == "team" then return end
    self:setNameColorStatus("team")
    self:updateNameColors()
end

function Character:toDynastyMyColor()
    if self:getNameColorStatus() == "dynastyMy" then return end
    self:setNameColorStatus("dynastyMy")
    self:updateNameColors()
end

function Character:toDynastyEnemyColor()
    if self:getNameColorStatus() == "dynastyEnemy" then return end
    self:setNameColorStatus("dynastyEnemy")
    self:updateNameColors()
end

function Character:updateNameColors()
    local status = self:getNameColorStatus()
    if status == "normal" then
        if self:isMySelf() then--自己252, 239, 223
            self:setNameColor(Res.PlayerNameColors.Self)
        else
            self:setNameColor(Res.PlayerNameColors.Other)
        end
    elseif status == "team" then
        self:setNameColor(Res.PlayerNameColors.Team)
    elseif status == "dynastyMy" then
        self:setNameColor(Res.PlayerNameColors.DynastyMy)
    elseif status == "dynastyEnemy" then
        self:setNameColor(Res.PlayerNameColors.DynastyEnemy)
    end
end

function Character:setNameColorStatus(status)
    self._nameColorStatus = status
end

function Character:getNameColorStatus()
    return self._nameColorStatus
end

function Character:addLevelupAnimation(animation)
    if animation then
        self._levelupAnimation = animation
        self:addChild(animation,1)
        NodeSetVisibleFunc(animation,false)
    end
end

function Character:playLevelUpAnimation()
    if not self._levelupAnimation then
        local animation = NodeFactory:createLevelUpAnimation()
        self._levelupAnimation = animation
        self:addChild(animation,1)
        NodeSetVisibleFunc(animation,false)
    end

    if not NodeIsVisibleFunc(self._levelupAnimation) then
        local function callback()
            NodeSetVisibleFunc(self._levelupAnimation,false)
        end
        AM.playSoundById(1018)
        NodeSetVisibleFunc(self._levelupAnimation,true)
        local play = self._levelupAnimation:play(Res.Effect_LevelUp.action,1,callback)
    end
end

function Character:getBonePos(bonePos)
    local posX, posY = 0,0
    local lvBonePos = bonePos or "body"
    if self.mRideArmature then
        posX, posY = self.mRideArmature:getBonePos(lvBonePos)
    elseif self.mArmatrueNode then
        posX, posY = self.mArmatrueNode:getBonePos(lvBonePos)
    end
    return posX, posY
end

function Character:playEquipAnimation(location)
    local param1
    local param2
    local bonePos1
    local bonePos2
    local pos
    local aniAction
    local job = UD:getClass()
    local scaleX = 1
    local isRide = self.mGetOnRide

    -- transDirection
    if self.mArmatrueNode then
        scaleX = self.mArmatrueNode:getScaleX()
        scaleX = scaleX / MathAbs(scaleX)
    end

    -- special(maybe is nil)
    if self._isEquipAnimationFinished then  --防止频繁点击
        if location == 1 then
            param2 = Res.Effect_Equip_Main_Weapon[job]
        else
            param2 = Res.Effect_Equip_Location[location]
        end
        if param2 then
            bonePos2 = param2.bonePos
            if isRide then
                aniAction = param2.rideAction
            else
                aniAction = param2.action
            end
        end
        local ani2 = NodeFactory:createEquipAnimation(location, job)
        if ani2 then    -- 部分部位没有对应特效
            self:addChild(ani2, 2)
            self._equipAnimation = ani2
            self._equipAnimation:setScaleX(scaleX)
            NodeSetVisibleFunc(self._equipAnimation, false)
        else
            self._equipAnimation = nil
        end

        if self._equipAnimation then
            pos = self:convertToNodeSpace(cc.p(self:getBonePos(bonePos2)))
            self._equipAnimation:setPosition(pos.x, pos.y)

            NodeSetVisibleFunc(self._equipAnimation, true)
            self._isEquipAnimationFinished = false
            self._equipAnimation:play(aniAction, 1, function()
                NodeSetVisibleFunc(self._equipAnimation, false)
                self._isEquipAnimationFinished = true
            end)
        end
    end

    -- common
    local index = job * 2 + UD:getGender()
    param1 = Res.Effect_Equip_Common[index]
    if param1 then
        bonePos1 = param1.bonePos
        if isRide then
            aniAction = param1.rideAction
        else
            aniAction = param1.action
        end
    end
    local ani1 = NodeFactory:createEquipCommonAnimation(index)
    self:addChild(ani1, 1)
    self._equipCommonAnimation = ani1
    self._equipCommonAnimation:setScaleX(scaleX)
    NodeSetVisibleFunc(self._equipCommonAnimation, false)

    --play
    if self._equipCommonAnimation then
        pos = self:convertToNodeSpace(cc.p(self:getBonePos(bonePos1)))
        self._equipCommonAnimation:setPosition(pos.x, pos.y)

        NodeSetVisibleFunc(self._equipCommonAnimation, true)
        self._equipCommonAnimation:play(aniAction, 1, function()
            NodeSetVisibleFunc(self._equipCommonAnimation, false)
        end)
    end
end

function Character:buildArmatureNode(callback)
    if not self.isUseAsyncLoad then
        --如果不使用异步加载,直接创建armature
        self:buildArmatureNodeReal()
        if callback then
            callback()
        end
        return
    end
    if self.isLoading then
        self.isNeedReLoad = true
        return -- 玩家外形有变化时，需要异步加载最新的资源
    end
    self.isLoading = true
    self.isNeedReLoad = false
    local AvatarFactory = app:getClass("AvatarFactory")

    AvatarFactory.preloadHero(self._userBaseInfo,function()
        if tolua.isnull(self) then return end
        self.isLoading = false
        if self.isNeedReLoad then
            self:buildArmatureNode()
        else
            self:buildArmatureNodeReal()
        end
        if callback then
            callback()
        end
    end)
end

function Character:buildArmatureNodeReal(armatureNode)
    local scaleX
    local scaleY
    if self.mArmatrueNode then
        scaleX = self.mArmatrueNode:getScaleX()
        scaleY = self.mArmatrueNode:getScaleY()
        self:removeChild(self.mArmatrueNode)
        self.mArmatrueNode = nil
        self.mRideArmature = nil
    end

    local AvatarFactory = app:getClass("AvatarFactory")
    self.mArmatrueNode = armatureNode and armatureNode or AvatarFactory.createHero(self._userBaseInfo)
    if self.mArmatrueNode then
        self:saveOriginalScale()
        self.mArmatrueNode:setAutoPlaySound(self:isMySelf())
        -- self.mArmatrueNode:setUpdateInterval(otherPlayerUpdateInterval) -- 其他玩家显示信息的更新频率，暂时先屏蔽，防止名字抖动

        self.mArmatrueNode:setAnchorPoint(cc.p(0.5,0))
        self:addChild(self.mArmatrueNode)
        if scaleX then self.mArmatrueNode:setScaleX(scaleX) end
        if scaleY then self.mArmatrueNode:setScaleY(scaleY) end

        self.mRideArmature = self.mArmatrueNode:getSlotDisplay("role")

        self:refreshArmatrueScale()

        self:adjustDirection()

        self:reloadAttachments()
    end

end

function Character:callArmatrueMethod(methodName,...)
    local method = self[methodName]
    if method then
        method(self,...)
    end
end

function Character:switchActions()
    --动作
    if self.mGetOnRide then
        self.ACTION_RUN = Role.ACTION_RIDE_MOVE--"mapmove"--跑动
        self.ACTION_IDLE = Role.ACTION_RIDE_IDLE--"mapidle"--待机
    else
        self.ACTION_RUN = Role.ACTION_MAP_MOVE--跑动
        self.ACTION_IDLE = Role.ACTION_MAP_IDLE --待机
        if self.SET_ACTION_RUN then
            self.ACTION_RUN = self.SET_ACTION_RUN
        end
    end
    self.ACTION_IDLE_B = "idle_b"
end

function Character:setRunAction(action)
    self.SET_ACTION_RUN = action
    self:switchActions()
end

function Character:playRideEffect(isGetOn)
    local Armature = app:getClass("Armature")
    local animation = Armature.create({
        path = Res.Effect_Ride.dir,
        armatureName = Res.Effect_Ride.name,
        animationName = "",
        skeletonName = Res.Effect_Ride.name
    })
    self:addChild(animation)
    local function callback()
        self:removeChild(animation)
    end
    local play = animation:play(Res.Effect_Ride.action,1,callback)

    if isGetOn then
        AM.playSoundById(2008)
    else
        AM.playSoundById(2009)
    end
end

---
--上坐骑
--
function Character:getOnRide(mountTid)
    if not mountTid then
        return
    end

    if mountTid == 0 then
        self:getOffRide()
        return
    end

    if self.mGetOnRide then
        return
    end

    self:changeMount(mountTid)
    AM.playSoundById(5092)
    -- local rideSpeed = self:getRideSpeed(mountTid)
    -- self.mRideSpeed = rideSpeed
    -- self:setSpeed(rideSpeed)

    if self.mArmatrueNode then
        self:adjustDirection()
--        self:playRideAction(self.ACTION_IDLE,0)
        self:forceStandby(false)

        if self:isMySelf() then
            self:playRideEffect(true)
            self:updateMainTaskEffectPos()
        end
    end
end

function Character:isGetOnRide()
    return self.mGetOnRide
end

function Character:setGetOffRideCallback(callback)
    self._getOffRideCallback = callback
end

function Character:callGetOffRide()
    if self._getOffRideCallback then
        self._getOffRideCallback()
    end
end

function Character:getOffRide(notSend)
    if self.mGetOnRide then
        self:changeMount(0)
        AM.playSoundById(5112)
        if self:isMySelf() and not notSend  then
            self:callGetOffRide()
        end

        -- self:setSpeed(self:getDefaultSpeed())

        self:adjustDirection()
        self:forceStandby(false)

        if self:isMySelf() then
            self:playRideEffect(false)
            self:updateMainTaskEffectPos()
        end
    end
end

function Character:getPointWorldPos()
    local x = 0
    local y = 0
    if self.mRideArmature then
        x,y = self.mRideArmature:getBoneWorldPosition("point")
        y = y - 10
    elseif self.mArmatrueNode then
        x,y = self.mArmatrueNode:getBoneWorldPosition("point")
    end

    return x,y
end

function Character:setChangeAvatarCallback(callback)
    self._changeAvatarCallback = callback
end

function Character:changeAvatarCallback(uid)
    if self._changeAvatarCallback then
        self._changeAvatarCallback(uid)
    end
end

function Character:changeAvatar(userBaseInfo)
    if self._userBaseInfo.classID ~= userBaseInfo.classID
        or self._userBaseInfo.gender ~= userBaseInfo.gender
        or self._userBaseInfo.hairColorID ~= userBaseInfo.hairColorID
        or self._userBaseInfo.faceID ~= userBaseInfo.faceID
        or self._userBaseInfo.hairID ~= userBaseInfo.hairID
        or self._userBaseInfo.raceID ~= userBaseInfo.raceID
        or self._userBaseInfo.sex ~= userBaseInfo.sex then
        self:changeAvatarCallback(userBaseInfo.uid)
        self._userBaseInfo = userBaseInfo:clone()
        self._userBaseInfo.inBattle = false
        self:getOffRide()
        self:buildArmatureNode(function()
            self:playAni(self:getCurAction(),0)
        end)
    else
        -- 自己通过changeEquip消息精准修改
        if not UD:isMe(userBaseInfo.uid) then
            self:changeEquips(userBaseInfo.fashionIDs)
        end
    end
end

-- 更新单个装备
-- userBaseInfo       创建角色的avatar userBaseInfo
-- fashionId    要替换的装备形象id
-- isOff        是否是卸装备
function Character:changeEquip(userBaseInfo, fashionId, isOff)
    self._userBaseInfo.fashionIDs = userBaseInfo.fashionIDs

    local AvatarFactory = app:getClass("AvatarFactory")
    AvatarFactory.changeEquip(self.mArmatrueNode, userBaseInfo, fashionId, isOff, self.mGetOnRide)
end

function Character:changeEquips(fashionIDs)
    if not fashionIDs then 
        return 
    end
    
    local curFashionIds = self._userBaseInfo.fashionIDs

    local isChanged = false
    if curFashionIds and #curFashionIds == #fashionIDs then
        for i,v in ipairs(fashionIDs) do
            if v ~= curFashionIds[i] then
                isChanged = true
                break
            end
        end
    else
        isChanged = true
    end

    if isChanged==true then
        self._userBaseInfo.fashionIDs = fashionIDs
        self:buildArmatureNode(function()
            self:playAni(self:getCurAction(),0)
        end)
        self:overEventActionPlaying()
    end
end

function Character:changeMount(mountTID)
    local mountId = tonumber(mountTID)
    if self:getMountId() ~= mountId then
        if mountId > 0 then
            self.mGetOnRide = true
        else
            self.mGetOnRide = false
        end
        self:setMountId(mountId)
        --print("====>changeMount ",mountId)
        self:switchActions()
        self:buildArmatureNode(function()
            self:playAni(self:getCurAction(),0)
        end)
    end
end

function Character:setBubbleEndCallback(callback)
    self._bubbleEndCallback = callback
end

function Character:callBubbleEnd()
    if self._bubbleEndCallback then
        self._bubbleEndCallback()
    end
end

function Character:setBubble(bubble)
    self.mBubble = bubble

    if bubble then
        self:addAttachment(bubble,"point",0,0)

        self.mBubble:setTouchEndCallback(function()
            self:callBubbleEnd()
        end)

        self:hideBubble()
    end
end

function Character:saveOriginalScale()
    if not self.mArmatrueNode then return end
    self.mOriginalScale = self.mArmatrueNode:getScale()
--    print("======saveOriginalScale:",self.mOriginalScale)
end

-- 设置地图的缩放
function Character:scaleTo(scale)
    self.mScale = scale
    if not self.mArmatrueNode then return end
    self.mArmatrueNode:setScale(self.mScale*self.mOriginalScale)

    self:transDirection()
end

function Character:refreshArmatrueScale()
    if not self.mArmatrueNode then return end
    self.mArmatrueNode:setScale(self.mScale*self.mOriginalScale)
end

function Character:getSelfScale()
    if not self.mArmatrueNode then 
        return 1.0
    else
        return self.mArmatrueNode:getScaleY()
    end
end

function Character:getIMBubble()
    return self.mIMBubble
end

function Character:setIMBubble(render)
    self.mIMBubble = render
    -- self:addChild(self.mIMBubble)
    NodeSetVisibleFunc(self.mIMBubble,false)
    self:addAttachment(render,"point",0,0)
end

function Character:showIMBubble(content, showTime, overCall)
    if self:isStopShowIMBubble() then return end
    if not self.mArmatrueNode then return end
    if not self.mIMBubble then return end
    showTime = tonumber(showTime or 5)
    NodeSetVisibleFunc(self.mIMBubble,true)
    if self.mIMAct then
        self.mIMBubble:stopAction(self.mIMAct)
        self.mIMAct = nil
    end

    self.mIMBubble:setContent(content)
    self.mIMBubble:play()
    
    local function callback()
        self.mIMAct = nil
        self:hideIMBubble()
        executeFunc(overCall)
    end
    local action = cc.Sequence:create(cc.DelayTime:create(showTime), cc.CallFunc:create(callback))
    self.mIMAct = self.mIMBubble:runAction(action)
end

function Character:hideIMBubble()
    if not self.mIMBubble then return end
    NodeSetVisibleFunc(self.mIMBubble,false)
    if self.mIMAct then 
        self.mIMBubble:stopAction(self.mIMAct)
    end
    self.mIMAct = nil
end

function Character:stopShowIMBubble(isStop)
    self._stopShowIMBubble = isStop
end

function Character:isStopShowIMBubble()
    return self._stopShowIMBubble
end

function Character:showBubble(content,showTime,overCall)
    if not self.mArmatrueNode then return end

    if cc.isDead(self.mBubble) then
        self.mBubble = NodeFactory:createBubble()
        self:addAttachment(self.mBubble,"point",0,0)

        self.mBubble:setTouchEndCallback(function()
            self:callBubbleEnd()
        end)
    end
--    if self.mBubble then
        self.mBubble:stopAllActions()

        if StoryManager:isEnterStoryMode() then
            self.mBubble:getParent():reorderChild(self.mBubble,SceneZOrder.storyModeUIOperateZOrder)
        else
            self.mBubble:getParent():reorderChild(self.mBubble,SceneZOrder.systemUIZOrder - 1)
        end

        --print("Character:showBubble ----- content = ",content)
        self.mBubble:setContent(content)
        self:transitionBubble()
        self.mBubble:runAnimation()
        
        local function callback()
            if overCall then
                overCall()
            end
        end
        if showTime then
            self.mBubble:runAction(cc.Sequence:create(cc.DelayTime:create(tonumber(showTime)),cc.CallFunc:create(callback)))
        end

        if DEBUG == -1 then
            self.mBubble:setVisible(false)
        end
--    end
end

function Character:hideBubble()
    if self.mBubble then
        self.mBubble:hide()
        self.mBubble:stopAllActions()

        self:removeAttachment(self.mBubble)
        self.mBubble:removeFromParent()
        self.mBubble = nil
    end
end

function Character:transitionBubble()
    if not self.mArmatrueNode then return end
    local flipX = self.mArmatrueNode:getScaleX()
    if self.mBubble then
        if flipX > 0 then
            self.mBubble:faceToRight()
        else
            self.mBubble:faceToLeft()
        end
    end
    if self.mIMBubble then
        self.mIMBubble:faceTo(flipX)
    end
end

-- 把玩家定在某一点（覆盖了targetX）
function Character:showLocationX(x)
    if not x then return end
    self:showLocation(x, 0)
    self:setTargetXValue(x) -- 设置目标点
    self:rayCastFoothold(x) -- 设置落脚点
end

-- 把玩家定在某一点 (不设置targetX)
function Character:showLocationXNotTarget(x)
    if not x then return end
    self:showLocation(x, 0)
    self:rayCastFoothold(x) -- 设置落脚点
end

function Character:setActionChangedCallback(callback)
    self._actionChangedCallback = callback
end

function Character:callActionChanged()
    if self._actionChangedCallback then
        self._actionChangedCallback()
    end
end

function Character:setAction(action, flagCallActionChange)
    if flagCallActionChange == nil then
        flagCallActionChange = true
    end
    if self.mAction ~= action then
        self._lastAction = self.mAction
        self.mAction = action
        if action == self.ACTION_RUN then
            if flagCallActionChange then
                self:callActionChanged()
            end
        elseif action == self.ACTION_IDLE then
            if self._lastAction == self.ACTION_RUN then
                if flagCallActionChange then
                    self:callActionChanged()
                end
            end
        end
    end
end

function Character:getCurAction()
    return self.mAction
end

function Character:isMove()
    if self:getCurAction() == self.ACTION_RUN then
        return true
    else 
        return false
    end
end
--
--function Character:getNormalX()
--    --local norX = math_floor(self:getPositionX() / self:getMoveRatiox())
--    return self.mNormalX
--end
--
--function Character:setNormalX(norX)
--    self.mNormalX = norX
--end

function Character:autoWayFinding(tarx)
    if not tarx then return end
    self:overEventActionPlaying()
    self:setAutoWayFinding(true)
    self.mSendToTaskTrack = false

    tarx = MathFloor(tarx)
    self.mAutoWayTargetX = tarx
    self:setTargetXValue(tarx)

    if self:getCurAction() ~= self.ACTION_RUN then
        --self:move(0,0)
        self:standby()
    end

    self:autoGetOnRide()
end

function Character:getAutoWayTargetX()
    return self.mAutoWayTargetX
end

function Character:setSendNextEventsCall(call)
    self._sendNextEventsCall = call
end

function Character:callSendNextEvents()
    if self._sendNextEventsCall then
        self._sendNextEventsCall()
    end
end

function Character:setAutoWayFinding(auto,nextEvents)
    if self:isEventActionPlaying() then return end
    if nextEvents == true and self.mAutoWayFinding == true and auto == false then
        if self:isMySelf() then
            local curX = MathFloor(NodeGetPositionXFunc(self))
            if self:getAutoWayTargetX() == curX then
                self:callSendNextEvents()
            end
        end
    end
    self.mAutoWayFinding = auto
    if auto then
        self:setAutoPatrol(false)
    end

    if not auto then
        if not self.mSendToTaskTrack then
            self.mSendToTaskTrack = true
            if self:isMySelf() then
                self:forceStandby()
                self:sendActionsEvent(self.ACTION_IDLE)
            end
        end
    end
end

function Character:isAutoWayFinding()
    return self.mAutoWayFinding
end

function Character:setAutoPatrol(auto,center,radius)
    -- 巡逻状态切换
    if self.mAutoPatrol ~= auto then
        executeFunc(self._onSwitchAutoPatrol, auto)
    end

    self.mAutoPatrol = auto
    self.mAutoPatrolCenter = center
    self.mAutoPatrolRadius = radius
    if auto then
        self:setAutoWayFinding(false,false)
        self:autoGetOnRide()
    end

    local headNameNode = self.mHeadNameNode
    if headNameNode then
        headNameNode:showPatrolName(auto)
        self:updateBehaviorPos()
    end
end

function Character:getPatrolCenter()
    return self.mAutoPatrolCenter
end

function Character:getPatrolRadius()
    return self.mAutoPatrolRadius
end

function Character:isAutoPatrol()
    return self.mAutoPatrol
end

function Character:onSwitchAutoPatrol(cb)
    self._onSwitchAutoPatrol = cb
end

function Character:updateAutoPatrol(dt)
    if self:isAutoPatrol() then

        local cx = MathFloor(NodeGetPositionXFunc(self))
        local blx = self.mAutoPatrolCenter - self.mAutoPatrolRadius
        local brx = self.mAutoPatrolCenter + self.mAutoPatrolRadius

        brx = self:roundPosition(brx)

        if self:getDirection() == Role.DIR_LEFT then
            if cx > blx then
                self:setPatrolTargetX(blx)
            else
                self:faceToDirectionNotPlayAction("right")
                self:setPatrolTargetX(brx)
            end
        elseif self:getDirection() == Role.DIR_RIGHT then
            if cx < brx then
                self:setPatrolTargetX(brx)
            else
                self:faceToDirectionNotPlayAction("left")
                self:setPatrolTargetX(blx)
            end
        end
    end
end

function Character:setMountId(mountId)
    self._userBaseInfo.mountID = tonumber(mountId)
end

function Character:setCharacterSpeed(speed)
    self._userBaseInfo.speed = tonumber(speed)
    self:setSpeed(self._userBaseInfo.speed)
end

function Character:isFaceToRight()
    if self:getDirection() == Role.DIR_RIGHT then
        return true
    else
        return false
    end
end

function Character:getMountId()
    return self._userBaseInfo.mountID or 0--self.mMountId
end

function Character:getEquips()
    return self._userBaseInfo.equips
end

function Character:setTargetXValue(tarx)
    if not tarx then return end
    self.mTargetX = MathFloor(self:roundPosition(tarx))
end

function Character:setTargetX(tarx,callback)
    if not tarx then return end
    if self.mTargetX == MathFloor(tarx) then return end
    self.mMoveOverCallback = callback
    self:setAutoWayFinding(false)
    self:setAutoPatrol(false)
    self:overEventActionPlaying()
    self:setTargetXValue(tarx)
    
--    if self:getCurAction() ~= self.ACTION_RUN then
--        self:move(0,0)
--    end

    self:autoGetOnRide()
end

function Character:autoGetOnRide()
    if self:isMySelf() and not self:isEventMove() and not StoryManager:isEnterStoryMode() then
        self:getOnRide(self:getMountId())
    elseif not self:isMySelf() then
        self:getOnRide(self:getMountId())
    end
end

function Character:setEventTargetX(tarx,speed,callback,lostDistance,lostFocus)
    if not tarx then return end
    self.mEventCallback = callback
    self.mEventMove = true

    self.mEventMoveStartX = NodeGetPositionXFunc(self)
    self.mLostFocusDistance = lostDistance
    self.mLostFocusCall = lostFocus

    local eventMoveSpeed = speed
    if not speed then
        eventMoveSpeed = self:getSpeed()
    end

    self:setEventMoveSpeed(eventMoveSpeed)
    self:setTargetX(tarx)
end

function Character:noticeEventLostFocus()
    if self.mEventMove and self.mLostFocusDistance then
        local moveDis = MathAbs(NodeGetPositionXFunc(self) - self.mEventMoveStartX)
        if moveDis >= self.mLostFocusDistance then
            if self.mLostFocusCall then
                self.mLostFocusCall()
                self.mLostFocusDistance = nil
            end
        end
    end
end

function Character:noticeEventMoveOver()
    if self.mEventMove then
        self.mEventMove = false
        if self.mEventCallback then
            self.mEventCallback()
        end
    end
end

function Character:noticeMoveOver()
    if not self.mStopMove then
        self.mStopMove = true
    end
    if not self:isMySelf() and not self:isEventActionPlaying() and not self:isEventMove() then
        if self:getCurAction() ~= self.ACTION_IDLE then
            self:forceStandby()
        end
    end
    
    if self.mMoveOverCallback then
        self.mMoveOverCallback()
        self.mMoveOverCallback = nil
    end

    self:noticeEventMoveOver()
end

function Character:isEventMove()
    return self.mEventMove
end

function Character:setEventMoveSpeed(speed)
    self.mEventMoveSpeed = speed
end

function Character:getEventMoveSpeed()
    return self.mEventMoveSpeed
end

function Character:setPatrolTargetX(tarx)
    if not tarx then return end
    self:setTargetXValue(tarx)
    
--    if self:getCurAction() ~= self.ACTION_RUN then
--        self:move(0,0)
--    end
end

function Character:getTargetX()
    return self.mTargetX
end

function Character:stopMove(immediately)
    if self:isEventActionPlaying() then return end

    self:setTargetX(NodeGetPositionXFunc(self))

    -- 立刻停止，而不是下一帧
    if immediately then
        self:updateFrame(0)
    end
end


function Character:setMySelf(mySelf)
    self.mMySelf = mySelf
end

function Character:isMySelf()
    return self.mMySelf
end

function Character:getArmatureNode()
    return self.mArmatrueNode
end

function Character:getRootArmature()
    return self.mRideArmature or self.mArmatrueNode
end

function Character:getBoundingBox()
    
    if self.mArmatrueNode then
        return self.mArmatrueNode:getBoundingBox()
    end
    
end

-- 头顶的 mHeadNameNode 也算
function Character:containWorldPoint(x,y)
    -- 先用x位置做一层过滤，距离在80之内的才有点中的可能
    local worldPos = self:getParent():convertToWorldSpace(cc.p(self:getPosition()))
    if math.abs(worldPos.x - x) > 80 then
        return false
    end

    if self.mArmatrueNode and self.mArmatrueNode:containWorldPoint(x,y) then
        return true
    end

    if self.mHeadNameNode and self.mHeadNameNode:containWorldPoint(x,y) then
        return true
    end

    return false
end

function Character:faceTo(targetX)
    local cx = NodeGetPositionXFunc(self)
    if cx < targetX then
        self:faceToRight()
    else
        self:faceToLeft()
    end
    self:standby()
end

---
-- 是否向左
--
function Character:isFaceToLeft()
    return self:getDirection() == Role.DIR_LEFT
end

---
-- 是否向右 
--
function Character:isFaceToRight()
    return self:getDirection() == Role.DIR_RIGHT
end

function Character:updateNameLabelVisibility(visible)
    if self.mLabelName then
        NodeSetVisibleFunc(self.mLabelName,visible)
    end
end

function Character:setGatherNode(gatherUi)
    if self.mGatherUi and gatherUi then
        self:removeAttachment(self.mGatherUi)
        self.mGatherUi:removeFromParent()
        self.mGatherUi = nil
    end
    self.mGatherUi = gatherUi
    if gatherUi then
        self:addAttachment(gatherUi,"point",0,0)
    end
end

function Character:setMatchNode(matchNode)
    assert(matchNode)
    assert(self.mMatchNode==nil)

    self.mMatchNode = matchNode

    local nameNode = matchNode:getChildByName("name")
    nameNode:setString(L("tips_3000105"))

    self:matchNodeVisibility(false)

    self:addAttachment(matchNode,"point",0,0)
end

function Character:matchNodeVisibility(visible)
    if self.mMatchNode then
        NodeSetVisibleFunc(self.mMatchNode,visible)
    end
end

function Character:removeBehaviorNode()
    if self.mBehaviorNode then
        self.mBehaviorNode:removeFromParent()
        self.mBehaviorNode = nil
    end
end

function Character:updateBehaviorNode(behavior, bloodData)
    local mark = nil

    local function updateBehavior()
        self._bloodData = nil
        if self._behavior == behavior then
            -- do nothing
        else
            self:removeBehaviorNode()
            mark = NodeFactory:createCharacterMark(behavior)
        end
        self._behavior = behavior
    end

    local function updateBlood()
        self._behavior = Enums.behaviorType.none
        if bloodData == nil then
            self:removeBehaviorNode()
        else
            if self._bloodData and self._bloodData.hp == bloodData.hp and self._bloodData.enemy == bloodData.enemy then
                -- do nothing
            else
                self:removeBehaviorNode()
                if bloodData.type == 2 then
                    mark = NodeFactory:createCharacterBlood2(bloodData.enemy, bloodData.hp)
                else
                    mark = NodeFactory:createCharacterBlood(bloodData.enemy, bloodData.hp)
                end
            end
        end
        self._bloodData = bloodData
    end

    -- 优先显示行为状态，再显示血量
    if behavior ~= Enums.behaviorType.none then
        updateBehavior()
    else
        updateBlood()
    end

    if not mark then return end

    self.mBehaviorNode = mark
    self:updateBehaviorPos()
    -- 是否显示头顶信息
    self:updateUpHead()
end

function Character:updateBehaviorPos()
    if not self.mBehaviorNode then return end
    local offset = 60
    if self.mHeadNameNode then 
        offset = self.mHeadNameNode:getNodeHeight()
    end
    self:addAttachment(self.mBehaviorNode,"point", 0, offset)
end

function Character:setNameNode(nameNode)
    assert(nameNode)
    assert(self.mHeadNameNode==nil)

    self.mHeadNameNode = nameNode

    self:setName("")
    self:setTitle("")
    self:setGuildName("")
    self:toNormalColor()

    self:addAttachment(nameNode,"point",0,0)

    -- 是否显示头顶信息
    self:updateUpHead()
end

function Character:setName(name)
    if not name then return end
    if self.mName == name then return end
    self.mName = name

    self.mHeadNameNode:setName(name)
    self:updateNameColors()
    self:updateBehaviorPos()
end

function Character:updateNameZOrder()
    local headNameNode = self.mHeadNameNode
    if  headNameNode then
        local line = self:getLine()
        local zOder = line*100 + NodeGetLocalZOrderFunc(self)
        NodeSetLocalZOrderFunc(headNameNode,zOder)
    end
end

function Character:setTitle(title,quality)
    if not title then return end
    if self.mTitle == title then return end

    self.mTitle = title
    local headNameNode = self.mHeadNameNode
    if headNameNode then
        headNameNode:setTitle(title)
        self:updateBehaviorPos()
        if title ~= "" then
            local color
            if quality then
                color = Res.medal_name_color[quality]
            else
                color = display.COLOR4_WHITE
            end
            if color then
                headNameNode:setTitleColor(color)
            end
        end
    end
end

-- ignoreTag 忽略 <>
function Character:setGuildName(guildName, ignoreTag)
    if not guildName then return end
    if self._guildName == guildName then return end

    ignoreTag = ignoreTag or false

    self._guildName = guildName
    local headNameNode = self.mHeadNameNode
    if headNameNode then
        if StringLen(guildName) > 0 then
            if not ignoreTag then
                guildName = "<" .. guildName .. ">"
            end
        end
        headNameNode:setGuildName(guildName)
        self:updateBehaviorPos()
    end
end

function Character:setGuildNameColor(color)
    if not color or not self.mHeadNameNode then return end
    if self._guildColor then
        if color.r == self._guildColor.r and
            color.g == self._guildColor.g and 
            color.b == self._guildColor.b and 
            color.a == self._guildColor.a then
            return
        end
    end
    self.mHeadNameNode:setGuildNameColor(color)
    self._guildColor = color
end

function Character:setLevel(lv)
    if not lv then return end
    self.mLevel = lv
    if self.mLabelLevel then
        self.mLabelLevel:setString(tostring(self.mLevel))
    end
end

function Character:getLevel()
    return self.mLevel
end


function Character:getArmature()
    return self.mArmatrueNode
end

function Character:setStopMoveCall(call)
    self._stopMoveCall = call
end

function Character:stopMoveCall()
    if self._stopMoveCall then
        self._stopMoveCall()
    end
end

function Character:sendActionsEvent(actionName)
    if actionName == self.ACTION_RUN then

    elseif actionName == self.ACTION_IDLE then
        if self:isMySelf() and not self:isAutoPatrol() then
            self:stopMoveCall()
        end
    end
end

function Character:prepareBattle()
    self:getOffRide()
    self:playAni("idle_b",0)
end

function Character:playAni(name,fadetime,callback,flagCallActionChange)
    --local aniName = CharacterAnimation[name]
--    if self:getCurAction() == name then
--        return
--    end
    if self:isEventActionPlaying() then
        return
    end
    self:playAniNotEvent(name,fadetime,callback,true,flagCallActionChange)
end

--function Character:playRideAction(name,fadetime,call)
--    if self.mArmatrueNode ~= nil then
--        self:setAction(name)
--        self.mArmatrueNode:play(name,-1,call)
--    end
--end

-- 简单播放动作
function Character:play(name, playtimes)
    if self.mArmatrueNode ~= nil then
        if self.mArmatrueNode:hasAnimation(name) then
            self.mArmatrueNode:play(name, playtimes or -1)
        end
    end
end

function Character:playAniNotEvent(name,fadetime,callback,send,flagCallActionChange)
    if send then
        self:sendActionsEvent(name)
    end

    local function call()
        if self:getCurAction() ~= self.ACTION_RUN then
            -- self:move(0,0)
            self:standby()
        end
        if callback then
            callback()
        end
    end
    self:switchActions()

    self:setAction(name, flagCallActionChange)

    if self.mArmatrueNode then
        self.mArmatrueNode:fadeIn(name,fadetime,-1,call)
    end
end

function Character:overEventActionPlaying()
    self.mEventActionPlaying = false
end

function Character:isEventActionPlaying()
    return self.mEventActionPlaying
end

function Character:playEventsAction(action,callback,delayTime,isLoop,tPlayTimes,tDuration,startCallback,overKeep)
    local function startCall()
        if startCallback then
            startCallback()
        end
    end

    local function call()
        self:overEventActionPlaying()
        if not self.mPlayEventActionOverKeep then
            self:standby()
        end
        if callback then
            callback()
        end
    end

    if not self.mArmatrueNode then
        startCall()
        call()
        return 0
    end
    self.mEventActionPlaying = true
    self.mPlayEventActionOverKeep = overKeep
    self.mArmatrueNode:stop()
    --self:setOpacity(0)
    delayTime = delayTime or 0
    local duration = tDuration or -1
    -- if self.mEventActionTag then
    --     self:stopActionByTag(self.mEventActionTag)
    -- end
    
    -- self.mEventActionTag = app:getTime() * 1000
    -- local sequenceAction = cc.Sequence:create(cc.DelayTime:create(delayTime),cc.CallFunc:create(function() 
    --         --self:setOpacity(255)
    --         self:stopActionByTag(self.mEventActionTag)
    --         self.mEventActionTag = nil
    --     end))
    
    -- sequenceAction:setTag(self.mEventActionTag)
    -- self:runAction(sequenceAction)

    local playTimes = -1
    if not isLoop then
        playTimes = 1
    end
    playTimes = tPlayTimes or playTimes

    local play = false
    if self.mArmatrueNode:hasAnimation(action) then
        startCall()
        play = self.mArmatrueNode:playAni({name = action,fadeInTime = 0,duration = duration,playTimes = playTimes,completeCallback = call})--,startCallback = startCall})--,loopCompleteCallback = call
    end

    if not play then
        call()
    else
        self:setAction(action, false)
    end

    return self.mArmatrueNode:getAniDuration(action)
end

function Character:attach(obj,offset)
    self:addChild(obj)
    NodeSetPositionFunc(obj,offset.x,offset.y)
end

-- 设落脚点
-- 根据x坐标取当前的y坐标
function Character:rayCastFoothold(newX)
    if not newX then return end
    newX = self:roundPosition(newX)

    local standY = MapManager:getStandPointY(self:getLine(), MathFloor(newX))

    self:showLocation(newX, standY)

    -- 更新自己的坐标点，抛出事件
    if self:isMySelf() then
        EM:notify("updateMyCharacterPos", newX)
    else
        -- 公会战 场景里，更新队长坐标
        if app:sendMsg("DynastyMapModel", "isDynastyMap") then
            EM:notify("updateOtherCharacterPos", {uid = self._userBaseInfo.uid, posX = newX})
        end
    end
end

function Character:setDirectionChangedCall(call)
    self._directionChangedCall = call
end

function Character:directionChangedCall()
    if self._directionChangedCall then
        self._directionChangedCall()
    end
end

function Character:decideDirChanged(changed)
    if self:isMySelf() and changed then
        self:directionChangedCall()
    end
end

function Character:isDirChanged(newDir)
    if self:getDirection() ~= newDir then
        return true
    end
    return false
end

function Character:faceToLeft()
    -- self.moveDir = cc.p(Role.DIR_LEFT,0)
    self.mDirectionX = Role.DIR_LEFT
    local changed = self:isDirChanged(Role.DIR_LEFT)
    self:setDirection(Role.DIR_LEFT)
    self:decideDirChanged(changed)
    -- self:updateAnimation()

--    self:resetRun()
    self:transDirection()
end

function Character:faceToRight()
    -- self.moveDir = cc.p(Role.DIR_RIGHT,0)
    self.mDirectionX = Role.DIR_RIGHT
    local changed = self:isDirChanged(Role.DIR_RIGHT)
    self:setDirection(Role.DIR_RIGHT)
    self:decideDirChanged(changed)
    -- self:updateAnimation()

--    self:resetRun()
    self:transDirection()
end

function Character:faceToDirectionNotPlayAction(dir)
    if dir == "left" then
        -- self.moveDir = cc.p(Role.DIR_LEFT,0)
        self.mDirectionX = Role.DIR_LEFT
        local changed = self:isDirChanged(Role.DIR_LEFT)
        self:setDirection(Role.DIR_LEFT)
        self:decideDirChanged(changed)
        self:transDirection()
    elseif dir == "right" then
        -- self.moveDir = cc.p(Role.DIR_RIGHT,0)
        self.mDirectionX = Role.DIR_RIGHT
        local changed = self:isDirChanged(Role.DIR_RIGHT)
        self:setDirection(Role.DIR_RIGHT)
        self:decideDirChanged(changed)
        self:transDirection()
    end
end

function Character:adjustDirection()
    if self:getDirection() == Role.DIR_LEFT then
        self:faceToLeft()
    else
        self:faceToRight()
    end  
end

---
-- 待机
--
function Character:standby()
    -- if self.moveDir.x == 0 and self.moveDir.y == 0 then
    --     return
    -- end
    if self:getCurAction() == self.ACTION_IDLE then
        self:sendActionsEvent(self.ACTION_IDLE)
        return
    end
    -- self:resetMoveDir()--dirX 1 向右 -1 向左
    -- self:updateAnimation()
    self:playAni(self.ACTION_IDLE,0)
    
end

function Character:forceStandby(flagCallActionChange)
    -- self:resetMoveDir()--dirX 1 向右 -1 向左
    -- self:updateAnimation()
--    self:setAction(self.ACTION_IDLE, flagCallActionChange)
    self:playAniNotEvent(self.ACTION_IDLE,0,nil,nil,flagCallActionChange)
end

-- function Character:resetMoveDir()
--     self.moveDir = cc.p(0,0)
-- end

function Character:move(dirX)
    if dirX == Role.DIR_LEFT then
        self:faceToLeft()
    elseif dirX == Role.DIR_RIGHT then
        self:faceToRight()
    else
        self:standby()
    end
end

function Character:transDirection()
    if not self.mArmatrueNode then return end
    local scaleX = self.mArmatrueNode:getScaleX()
    local slx = -self.mDirectionX * MathAbs(scaleX)

    self.mArmatrueNode:setScaleX(slx)
    self:transitionBubble()
end

function Character:updateAnimation()
    if self.moveDir.x ~= 0 then
        self:resetRun()
        self:transDirection()
    else
        self:playAni(self.ACTION_IDLE,0)
    end
end

function Character:resetRun()
    if self:getCurAction() ~= self.ACTION_RUN then
        self:playAni(self.ACTION_RUN,0.2)
    end
end

-- 播放星空谜棋方向动画
function Character:playChessAction(isForward)
    if not self._chessNode then
        local node = cc.CSLoader:createNode(Res.ChessArrowNode, true)
        node:setPositionY(100)
        self:addChild(node, 1)
        self._chessNode = node
    end

    local node = self._chessNode
    node:setVisible(true)
    node:findChild("Panel/go"):setVisible(isForward)
    node:findChild("Panel/remove"):setVisible(not isForward)
    node:setPositionX(isForward and 70 or -70)
    node:getTimeline():gotoFrameAndPlay(0, true)
end

-- 停止星空谜棋方向动画
function Character:stopChessAction()
    if self._chessNode then
        self._chessNode:setVisible(false)
        self._chessNode:getTimeline():pause()
    end
end

function Character:removeBuffNode()
    if self.mBuffNode then
        self.mBuffNode:removeFromParent()
        self.mBuffNode = nil
    end
end

-- 播放buff动画
function Character:playCharacterBuff(buff)
    if self._buffData == buff then return end
    self:removeBuffNode()
    self._buffData = buff

    if not self._buffData then return end

    local armature = NodeFactory:createCharacterBuff(buff)
    armature:setPosition(cc.p(0, 0))
    self:addChild(armature, 2) -- 特效添加到人物身上, 添加到上层
    self.mBuffNode = armature
    
end

function Character:removeMainTaskEffect()
    if self.mMainTaskEffectNode then
        self.mMainTaskEffectNode:removeFromParent()
        self.mMainTaskEffectNode = nil
    end
end

-- 更新主线任务特效的位置（位置绑定bone，切换坐骑时更新位置）
function Character:updateMainTaskEffectPos()
    if not self._mainTaskBuff or not self.mMainTaskEffectNode then return end
    local info = Enums.mainTaskEffect[self._mainTaskBuff]
    if not info then return end
    local pos = self:convertToNodeSpace(cc.p(self:getBonePos(info.boneName)))
    self.mMainTaskEffectNode:setPosition(pos.x, pos.y)
end

-- 播放主线任务特效动画
function Character:playCharacterMainTaskEffect(buffName)
    if self._mainTaskBuff == buffName then return end
    self:removeMainTaskEffect()
    self._mainTaskBuff = buffName
    if not self._mainTaskBuff then return end
    local info = Enums.mainTaskEffect[self._mainTaskBuff]
    if not info then return end

    local armature = NodeFactory:createCharacterMainTaskBuff(buffName)
    self:addChild(armature, -1) -- 特效添加到人物身上, 添加到下层
    self.mMainTaskEffectNode = armature

    self:updateMainTaskEffectPos()
end 

local CharacterUpdateAutoPatrol = Character.updateAutoPatrol
local CharacterUpdatePlayStyleAction = Character.updatePlayStyleAction
local CharacterSetAutoWayFinding = Character.setAutoWayFinding
local CharacterMove = Character.move
local CharacterNoticeMoveOver = Character.noticeMoveOver
local CharacterGetCurAction = Character.getCurAction
local Constant = _G["Constant"]

function Character:setMapPositionError(position)
    self._mapPositionError = position
end

function Character:updateFrame(dt)
    if not NodeIsVisibleFunc(self) then
        return
    end

    CharacterUpdateAutoPatrol(self,dt)
    CharacterUpdatePlayStyleAction(self,dt)

    local curPosXFloat,curPosY = NodeGetPositionFunc(self)
    local curPosX = MathFloor(curPosXFloat)
    local targetX = self.mTargetX or curPosX
    -- targetX = self:roundPosition(targetX)
    local flagInMyTeam = TeamManager:isEnitityInMyTeam(self:getUid())
    local dis = MathAbs(targetX - curPosX)
    if (not self.mMySelf and flagInMyTeam and dis > Constant.MapTeamPositionError) or
       (not self.mMySelf and not flagInMyTeam and dis > (self._mapPositionError or Constant.MapPositionError)) or
       (self.mMySelf and dis > 0) then
        self.mStopMove = false

        self:noticeEventLostFocus()

        if curPosX < targetX then
            CharacterMove(self, Role.DIR_RIGHT)
        elseif curPosX > targetX then
            CharacterMove(self, Role.DIR_LEFT)
        end

        self:resetRun()
        
        local disX = 0
        if self:isEventMove() then
            disX = self:getEventMoveSpeed() * dt
        else
            disX = self:getSpeed() * dt
        end

        local moveDirX = self.mDirectionX
        local newX = curPosXFloat + disX * moveDirX
        if moveDirX == 1 then--向右
            if newX > targetX then
                newX = targetX
            end
        else-- 向左
            if newX < targetX then
                newX = targetX
            end
        end
        self:rayCastFoothold(newX)
    else
        if CharacterGetCurAction(self) == self.ACTION_RUN then
            CharacterMove(self, 0)
            local entity
            if flagInMyTeam then
                local teamLeaderId = TeamManager:getTeamLeaderId()
                if not self.mMySelf or (self.mMySelf and self:getUid() ~= teamLeaderId) then
                    entity = FieldManager:getEntityById(teamLeaderId)
                end
            elseif not self.mMySelf then
                entity = FieldManager:getEntityById(self:getUid())
            end
            if entity then
                if entity:isFaceToLeft() then
                    self:faceToDirectionNotPlayAction("left")
                else
                    self:faceToDirectionNotPlayAction("right")
                end
            end
        end
        CharacterSetAutoWayFinding(self,false,true)
        CharacterNoticeMoveOver(self)
    end
    
end


return Character